package at.donalfonso.ui.pizzeria;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.Serializable;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.Topic;
import javax.swing.DefaultListModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.donalfonso.model.Bestellung;
import at.donalfonso.model.Gruppe;
import at.donalfonso.model.GruppeStatus;
import at.donalfonso.model.Pizza;
import at.donalfonso.model.Tisch;
import at.donalfonso.model.Tisch.TischStatus;
import at.donalfonso.utility.JMSUtility;

public class PizzeriaControllerJMS implements ActionListener, WindowListener, MessageListener {

	private DefaultListModel<Gruppe> gruppeModel = new DefaultListModel<Gruppe>();
	private DefaultListModel<Tisch> tischModel = new DefaultListModel<Tisch>();
	private DefaultListModel<Bestellung> bestellModel = new DefaultListModel<Bestellung>();
	private DefaultListModel<Integer> platzModel = new DefaultListModel<Integer>();
	private Integer freiePlaetze = 0;

	private JMSUtility jmsUtility = null;

	private PizzeriaView gui;
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	private String hoechsteBestellID;
	
	public int filiale;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		int filiale;
		if (args.length > 0) {
			filiale = Integer.parseInt(args[0]);
		}
		else {
			System.out.println("Bitte geben Sie die Nummer der Filiale (1 oder 2) als Parameter mit.");
			filiale = 1;
		}
		
		PizzeriaControllerJMS controller = new PizzeriaControllerJMS(filiale);
		controller.run();
	}

	public PizzeriaControllerJMS(int filiale){

		this.filiale = filiale;
		
		try {
			//"com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
			//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {

			e.printStackTrace();
		}


		/* Broker initialisieren */
		//getJMSUtility().runBroker();
		
		gui = new PizzeriaView(gruppeModel, tischModel, bestellModel, platzModel);
		gui.addWindowListener(this);
		gui.setTitle("Don Alfonso: PizzeriaGUI JMS. Filiale "+filiale);

		platzModel.addElement(new Integer(0));
		platzModel.setSize(1);

		try {

			// Verbindung zum ActiveMQ Server wird hergestellt.
			getJMSUtility().getConnection().start();
			
			// Lösche die alten Einträge
			getJMSUtility().purgeQueues();

		} catch (JMSException e2) {
			e2.printStackTrace();
		}
	}

	public void run(){
		try {
			
			/* Alle GUI relevanten Events werden über das GUI-Topic empfangen. */

			Topic guiTopic = getJMSUtility().getTopicGuiUpdate();
			getJMSUtility().getSession().createConsumer(guiTopic).setMessageListener(this);


			Thread.sleep(1000);

			Queue queue = getJMSUtility().getQueueSaal();
			MessageProducer producer = getJMSUtility().getSession().createProducer(queue);

			getJMSUtility().getConnection().start();

			/* Erzeugen der Tische */
			for (int i=0; i < 10; i++) {
				Tisch tisch = new Tisch();

				ObjectMessage om = getJMSUtility().getSession().createObjectMessage(tisch);
				om.setStringProperty("Class", tisch.getClass().getSimpleName());
				om.setStringProperty("ID", tisch.getId());
				om.setStringProperty("TischStatus", tisch.getStatus().toString());
				
				producer.send(om);
				updateGui(tisch);
				logger.debug("Tisch gesendet");
			}
			
			erzeugeNeueBestellungen();
			
			/* zum Testen:
			Gruppe gruppe = new Gruppe(PizzaEnum.CARDINALE, null, null, null);
			ObjectMessage om = getJMSUtility().getSession().createObjectMessage(gruppe);
			om.setStringProperty("ID", gruppe.getId());
			om.setStringProperty("STATUS", gruppe.getStatus().toString());
			
			producer.send(om);
			*/
		} catch (JMSException e) {
			e.printStackTrace();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
	}
	
	public void erzeugeNeueBestellungen() throws JMSException {
		Session session = getJMSUtility().getSession();
		MessageProducer prod = session.createProducer(getJMSUtility().getQueueBestellungNeu());
		Bestellung b = null;
		ObjectMessage om;
		
		for (int i = 1; i < 200; i++) {
			b = new Bestellung(filiale);
			om = session.createObjectMessage(b);
			prod.send(om);
		}
		
		hoechsteBestellID = b.getBestellungId();
	}

	@Override
	public void onMessage(Message message) {

		logger.debug("in onMessage() "+message);

		try {
			
			if (message instanceof ObjectMessage) {
				Serializable s = null;

				s = ((ObjectMessage) message).getObject();

				if (s instanceof Tisch) {
					
					Tisch t = (Tisch) s;
					logger.debug("Tisch empfangen: " + t);

					if (t.getStatus().equals(TischStatus.FREI))
						freiePlaetze += t.getPlaetze();
					if (t.getStatus().equals(TischStatus.BESETZT))
						freiePlaetze -= t.getPlaetze();
					platzModel.set(0, freiePlaetze);

					int index = tischModel.indexOf(t);
					if (index < 0)
						tischModel.addElement(t);
					else
						tischModel.set(index, t);
				}
				if (s instanceof Gruppe) {
					
					Gruppe gruppe = (Gruppe) s;
					logger.debug("Gruppe empfangen: " + gruppe + "("+gruppe.getStatus()+")");
										
					if (gruppe.getStatus() == GruppeStatus.WARTEN)
						gruppeModel.addElement(gruppe);
					else
						gruppeModel.removeElement(gruppe);
				}

				if (s instanceof Bestellung) {
					Bestellung b = (Bestellung) s;
//					logger.debug("Bestellung empfangen: " + b);
//					logger.debug("Absender: " + message.getStringProperty("Sender"));
					
					int index = bestellModel.indexOf(b);
					if (index < 0)
						bestellModel.addElement(b);
					else
						bestellModel.set(index, b);
	
					// Bestellungen werden wegen eindeutigen IDs hier erzeugt
					// wenn Vorrat erschöpft, neue erzeugen
					if (b.getBestellungId().equals(hoechsteBestellID))
						erzeugeNeueBestellungen();
				}

				if (s instanceof Pizza) {
					Pizza pizza = (Pizza) s;
					logger.debug("Pizza empfangen: " + pizza);
										
					/* Bestellung zur Pizza ermitteln */

					for (int i=0; i < bestellModel.size(); i++) {
						Bestellung b = bestellModel.get(i);
						if (b.getBestellungId().equals(pizza.getBestellnummer())){
							b.replacePizza(pizza);
							bestellModel.set(i, b);
						}
					}
				}
			}
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub

	}


	@Override
	public void windowActivated(WindowEvent arg0) {

	}

	@Override
	public void windowClosed(WindowEvent arg0) {

	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		try {
			getJMSUtility().getSession().close();
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		logger.info("Shutdown.");
		System.exit(0);
	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {

	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {

	}

	@Override
	public void windowIconified(WindowEvent arg0) {

	}

	@Override
	public void windowOpened(WindowEvent arg0) {

	}

	/**
	 * Über das Topic "Gui_update" werden Statusänderungen kommuniziert.
	 */
	public void updateGui(Serializable object){

		logger.debug("Updating Gui.");

		try {
			Topic topic = getJMSUtility().getTopicGuiUpdate();
			Message msg = getJMSUtility().getSession().createObjectMessage(object);

			MessageProducer producer = getJMSUtility().getSession().createProducer(topic);

			producer.send(msg);

			producer.close();

		} catch (JMSException e) {

			logger.debug("GUI Update failed.");

			e.printStackTrace();
		}	
	}	

	public JMSUtility getJMSUtility(){
		if (jmsUtility == null){
			jmsUtility = new JMSUtility(filiale);
		}
		return jmsUtility;
	}
}
